
[bits 32]
%define ERROR_CODE nop ; 若CPU压入了错误码，则无需操作
%define ZERO push 0    ; 若CPU没有压入错误码，则需要手动压入错误码，保证格式统一

extern idt_table

section .data
global intr_entry_table
intr_entry_table:

%macro VECTOR 2     ; %1:中断向量号, %2:对压入 ERROR_CODE 的处理
section .text
intr%1entry:        ; 中断处理程序的起始处

    %2

    push ds         ;\
    push es         ; |因为要调用C的中断核心处理函数
    push fs         ; |因此要“手动”保护现场
    push gs         ; |Tips：在此之前，即进入中断前，CPU已经自动将 EFLSG、CS、IP 压入栈中，若中断有错误码，则也会压入。
    pushad          ;/

    ; 若是从片上发送的中断，则除了向从片发送 EOI 外，还需要往主片发送 EOI
    mov al, 0x20    ; 中断结束命令 EOI
    out 0xa0, al    ; 向从片发送
    out 0x20, al    ; 向主片发送

    push %1
    call [idt_table + %1 * 4]
    jmp intr_exit

section .data       ; 编译器会将属性相同的 section 合并到同一个大的 segment 中
    dd intr%1entry  ; 存储各个中断入口程序的地址

%endmacro

section .text
global intr_exit
intr_exit:
    add esp, 4 ; 通过中断号
    popad
    pop gs
    pop fs
    pop es
    pop ds
    add esp, 4 ; 通过 ERROR_CODE
    iretd

VECTOR 0x00,ZERO
VECTOR 0x01,ZERO
VECTOR 0x02,ZERO
VECTOR 0x03,ZERO 
VECTOR 0x04,ZERO
VECTOR 0x05,ZERO
VECTOR 0x06,ZERO
VECTOR 0x07,ZERO 
VECTOR 0x08,ERROR_CODE
VECTOR 0x09,ZERO
VECTOR 0x0a,ERROR_CODE
VECTOR 0x0b,ERROR_CODE 
VECTOR 0x0c,ZERO
VECTOR 0x0d,ERROR_CODE
VECTOR 0x0e,ERROR_CODE
VECTOR 0x0f,ZERO 
VECTOR 0x10,ZERO
VECTOR 0x11,ERROR_CODE
VECTOR 0x12,ZERO
VECTOR 0x13,ZERO 
VECTOR 0x14,ZERO
VECTOR 0x15,ZERO
VECTOR 0x16,ZERO
VECTOR 0x17,ZERO 
VECTOR 0x18,ERROR_CODE
VECTOR 0x19,ZERO
VECTOR 0x1a,ERROR_CODE
VECTOR 0x1b,ERROR_CODE 
VECTOR 0x1c,ZERO
VECTOR 0x1d,ERROR_CODE
VECTOR 0x1e,ERROR_CODE
VECTOR 0x1f,ZERO 
VECTOR 0x20,ZERO

